const VSHADER_SOURCE = `
  attribute vec4 a_Position;
  attribute vec4 a_Color;
  attribute vec4 a_Normal;
  uniform mat4 u_CameraMatrix;
  uniform mat4 u_ModelMatrix;
  uniform vec3 u_LightColor;
  uniform vec3 u_LightDirection;
  uniform vec3 u_AmbColor;
  uniform vec3 u_PointColor;
  uniform vec4 u_PointPosition;
  varying vec4 v_Color;
  void main(){
    // 获取点光源方向
    vec3 pointLightDirection = normalize(vec3(u_PointPosition - a_Position)); 
    // 平行光法向量
    vec3 normal = normalize(vec3( u_ModelMatrix * a_Normal));
    // 点光源方向 & 法向量 点积
    float pointDot = max(dot(pointLightDirection,normal),0.0);
    // 光纤方向和法向量点积
    float nDotL = max(dot(u_LightDirection,normal),0.0);
    // 环境光
    vec3 ambient = u_AmbColor * a_Color.rgb;
    // 计算漫反射光的颜色
    vec3 diffuse = u_LightColor * a_Color.rgb * nDotL;
    // 点光源颜色
    vec3 pointColor = pointDot * u_PointColor;
    gl_Position = u_CameraMatrix * a_Position;
    v_Color = vec4(diffuse + ambient + pointColor,a_Color.a);
  }
`

const FSHADER_SOURCE = `
  #ifdef GL_ES
  precision mediump float; 
  #endif
  varying vec4 v_Color;
  void main(){
    gl_FragColor = v_Color;
  }
`

var a_Position, a_Color, u_CameraMatrix, a_Normal,
  u_PointColor, u_PointPosition, u_LightColor, u_LightDirection, u_AmbColor, u_ModelMatrix,
  vshaderBuf, normalBuf, indicesBuf, colorBuf, transformMatrix;
var canvas, gl, ang = 0;

var cameraParam = {
  x: 3,
  y: 3,
  z: 7,
  atX: 0,
  atY: 0,
  atZ: 0,
  upX: 0,
  upY: 1,
  upZ: 0,
  near: 1,
  far: 800,
  fov: 45,
  aspect: 1,
}

// var vshaderArr = new Float32Array([
//   -1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
//   -1.0, -1.0, 1.0, 1.0, 0.0, 0.0,
//   1.0, -1.0, 1.0, 1.0, 0.0, 0.0,
//   1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
//   1.0, 1.0, -1.0, 1.0, 0.0, 0.0,
//   -1.0, 1.0, -1.0, 1.0, 0.0, 0.0,
//   -1.0, -1.0, -1.0, 1.0, 0.0, 0.0,
//   1.0, -1.0, -1.0, 1.0, 0.0, 0.0,
// ])
// var vshaderArr = new Float32Array([
//   1.0, 1.0, 1.0, , 1.0, 0.0, 0.0,
//   -1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
//   -1.0, -1.0, 1.0, 1.0, 0.0, 0.0,
//   1.0, -1.0, 1.0, 0.0, 0.0,
//   1.0, -1.0, -1.0, 1.0, 0.0, 0.0,
//   -1.0, -1.0, -1.0, 0.0, 0.0,
//   -1.0, 1.0, -1.0, 1.0, 0.0, 0.0,
//   1.0, 1.0, -1.0, 1.0, 0.0, 0.0,
// ])
var vshaderArr = new Float32Array([
  1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, // v0-v1-v2-v3 front
  1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, // v0-v3-v4-v5 right
  1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, // v0-v5-v6-v1 up
  -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, // v1-v6-v7-v2 left
  -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, // v7-v4-v3-v2 down
  1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0 // v4-v7-v6-v5 back
])

// Colors
var colorArr = new Float32Array([
  1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v1-v2-v3 front
  1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
  1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v5-v6-v1 up
  1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v1-v6-v7-v2 left
  1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v7-v4-v3-v2 down
  1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 // v4-v7-v6-v5 back
]);

var normalArr = new Float32Array([
  0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front
  1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
  0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
  -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
  0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, // v7-v4-v3-v2 down
  0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0 // v4-v7-v6-v5 back
])

// var vshaderIndicesArr = new Uint8Array([
//   0, 1, 2, 0, 2, 3, // front,
//   3, 2, 7, 3, 7, 4, // right
//   0, 4, 5, 0, 3, 4, // up
//   0, 5, 6, 0, 6, 1, // left
//   1, 6, 7, 1, 7, 2, // bottom
//   4, 5, 6, 4, 6, 7 // back
// ])
var vshaderIndicesArr = new Uint8Array([
  0, 1, 2, 0, 2, 3, // front
  4, 5, 6, 4, 6, 7, // right
  8, 9, 10, 8, 10, 11, // up
  12, 13, 14, 12, 14, 15, // left
  16, 17, 18, 16, 18, 19, // down
  20, 21, 22, 20, 22, 23 // back
])

function initEnv() {
  canvas = document.getElementById("example");
  transformMatrix = new Matrix4();

  gl = getWebGLContext(canvas);
  gl.clearColor(0, 0, 0, 1);
  gl.enable(gl.DEPTH_TEST);
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.error("initEnv");
  }

  a_Position = gl.getAttribLocation(gl.program, "a_Position");
  a_Color = gl.getAttribLocation(gl.program, "a_Color");
  a_Normal = gl.getAttribLocation(gl.program, "a_Normal");

  u_CameraMatrix = gl.getUniformLocation(gl.program, "u_CameraMatrix");
  u_ModelMatrix = gl.getUniformLocation(gl.program, "u_ModelMatrix");
  u_LightColor = gl.getUniformLocation(gl.program, "u_LightColor");
  u_AmbColor = gl.getUniformLocation(gl.program, "u_AmbColor");
  u_LightDirection = gl.getUniformLocation(gl.program, "u_LightDirection");
  u_PointColor = gl.getUniformLocation(gl.program, "u_PointColor");
  u_PointPosition = gl.getUniformLocation(gl.program, "u_PointPosition");

  if (a_Position < 0 || !a_Color || !u_CameraMatrix || !a_Normal || !u_ModelMatrix ||
    !u_LightColor || !u_LightDirection || u_AmbColor) {
    console.error("initEnv", u_CameraMatrix, u_LightColor, u_ModelMatrix, u_LightDirection, u_AmbColor);
  }
}

function initVertices() {
  const FSIZE = vshaderArr.BYTES_PER_ELEMENT;
  var lightDirection = new Vector3([1.0, 10.0, 5.0]);
  var modelMatrix = new Matrix4();
  var tmpMatrix = new Matrix4();

  vshaderBuf = gl.createBuffer();
  indicesBuf = gl.createBuffer();
  normalBuf = gl.createBuffer();
  colorBuf = gl.createBuffer();

  transformMatrix.setPerspective(cameraParam.fov, cameraParam.aspect, cameraParam.near, cameraParam.far);
  transformMatrix.lookAt(
    cameraParam.x, cameraParam.y, cameraParam.z,
    cameraParam.atX, cameraParam.atY, cameraParam.atZ,
    cameraParam.upX, cameraParam.upY, cameraParam.upZ
  );
  transformMatrix.rotate(ang, 0, 1, 0);
  tmpMatrix.setRotate(ang, 0, 1, 0);

  gl.uniformMatrix4fv(u_CameraMatrix, false, transformMatrix.elements);
  modelMatrix.setInverseOf(tmpMatrix);
  tmpMatrix.transpose();
  gl.uniformMatrix4fv(u_ModelMatrix, false, tmpMatrix.elements);

  // Set the light color (white)
  gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
  lightDirection.normalize(); // Normalize
  gl.uniform3fv(u_LightDirection, lightDirection.elements);
  // gl.uniform3f(u_AmbColor, 0.2, 0.2, 0.2);
  // gl.uniform3f(u_PointColor, 0.0, 0.5, 0.0);
  gl.uniform4f(u_PointPosition, 4, 1, 4,1);

  gl.bindBuffer(gl.ARRAY_BUFFER, normalBuf);
  gl.bufferData(gl.ARRAY_BUFFER, normalArr, gl.STATIC_DRAW);
  gl.vertexAttribPointer(a_Normal, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(a_Normal);

  gl.bindBuffer(gl.ARRAY_BUFFER, vshaderBuf);
  gl.bufferData(gl.ARRAY_BUFFER, vshaderArr, gl.STATIC_DRAW);
  gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(a_Position);

  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuf);
  gl.bufferData(gl.ARRAY_BUFFER, colorArr, gl.STATIC_DRAW);
  gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(a_Color);

  gl.bindBuffer(gl.ARRAY_BUFFER, null);
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuf);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, vshaderIndicesArr, gl.STATIC_DRAW);
}

function init() {
  initEnv();
  initVertices();
}

function animate() {
  ang = (ang + 3) % 360;
  // ang = 180;
  initVertices();
  render();
  requestAnimationFrame(animate);
}

function render() {
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  gl.drawElements(gl.TRIANGLES, vshaderIndicesArr.length, gl.UNSIGNED_BYTE, 0);
}

function main() {
  init();
  animate();
}